Implementing Customer Reports Using the KM Reporting API


Table of Contents

Summary

Prerequisites and Relevant Knowledge Management APIs

Coding in Detail

Implementing the IReportInterface

Lifetime of a Report

Configuration

Preparing the Configurables on IDE Level

Adding the Report to the Reporting Repository

Example


Summary

Since reporting was introduced in the KM application, it is a commonly used feature in many customer projects. Besides the standard reports, customers want to extend the reporting repository by adding their own reports for specific reporting activities. The new Reporting API offers the possibility to implement customer specific reports for this purpose.

Prerequisites and Relevant Knowledge Management APIs

A prerequisite for developers starting to use the Reporting API is an understanding of the concepts described in Repository Framework Concepts (RCO) and advanced knowledge of the KM configuration for repository managers and reports.

This tutorial describes the implementation of customer reports using the Reporting API of KM. The following Knowledge Management API package is used in the sample implementation:

Coding in Detail

The Reporting API offers the possibility to track information related to resource or collection objects within the landscape of repositories. Developing custom reports means implementing a certain interface and registering the report implementation on the Report Repository Manager. This sample report implements the tracking of empty folders in the specified repositories.

Implementing the IReportInterface

The main purpose of a report implementation is the execution of the report on certain resources. Therefore the critical method to implement it is the execute()method with different signatures:

 
         public IReportResult execute(
                 IReportInput input, 
                 IResourceContext ctx, 
                 IResultReceiver receiver) 
                 throws ResourceException, InterruptedException {
                          

The initial task of the execute() method is to retrieve the user input parameters of the configuration. All parameters set by the user interface are provided through the IReportInputobject passed to the execute() method. The parameters themselves must be evaluated by the report implementation.

                 IProperty pr = input.getParameters().get(m_hidden);
                 boolean isHidden = false; 
                 if (pr != null) {
                          isHidden = pr.getBooleanValue();
                 }

The resources that the report runs on are kept in the report's scope, which is provided by the scope controller. Basically, the scope controller can provide multiple scopes in one execution cycle. A single scope is represented as an RID object.

         for (Iterator it = input.getScope().iterator(); it.hasNext();) {
                 RID rid = (RID)it.next();
         }

The investigating()method of the result receiver keeps track of the current scope that the execute()method is processing.

receiver.investigating(rid);

Now the execution of the report can be started. In this sample, the execution is done recursively and is encapsulated in a separate method called internalExecute().

this.internalExecute(rid, ctx, receiver, isHidden);

Let's have a detailed look at this methods implementation:

 
private void internalExecute(RID rid, IResourceContext ctx, 
         IResultReceiver receiver, boolean isHidden) throws
         ResourceException, InterruptedException {
                 

In a first step the RIDobject has to be transformed into an IResourceobject.

IResource res = ResourceFactory.getInstance().getResource(rid, ctx);

Our check criteria for this report is an empty folder check, therefore we check for the collection and retrieve the ChildrenCount attribute from it:

                   if (res.isCollection()) {                       int childrenCount = ((ICollection)res). 
                       getChildrenCount(!isHidden,true,true);
                       if (childrenCount==0) {

If the check is passed, the reporting to the result receiver must be done. Every resource result has to be stored in a result item object and passed to the result receiver. The ResultItemaccepts a list of result properties stored in a Map object.

               Map pm = new HashMap();
                                              
               pm.put(
               SimpleReport.m_sapDisplayname, 
                       new Property(SimpleReport.m_sapDisplayname, 
                               res.getDisplayName())
               ); 
                                              
               receiver.addItem(
                     ResultItem.getInstance(rid, pm, new ArrayList(),true, 
                       this.getEmptyStatus(ctx.getLocale()))
               ); 
               

If a result is not valid or fails, it can also store an error message to the result receiver.

receiver.addError(rid, "An error has occurred.", ex);

At the end the result receiver has to be finished and return the result of the receiver.

return receiver.finish("", SimpleReport.m_resultPropertyNames);

Every reports result is based on a set of properties that are reported to the result receiver. The properties must be defined in the report itself and can be declared as final static objects in the implementation class.

private static final IPropertyName m_sapDisplayname;

The static properties have to be initialized in a static block of the implementation class.

         
         static {
                 m_sapDisplayname = PropertyName.createDisplayname();
         } 

Besides the standard CM properties, you can also use custom properties, either modeled or unmodeled.

If the report should support any parameters for configuration and flexibility purposes, a set of the report's metadata can also be specified in the static part of the report.

private static final IPropertyName m_hidden;
private static final List m_parameterNames; 
private static final Map m_parameterDefinitions; 
private static final Map m_parameterDefaults;
private static final IReportInputMeta m_meta; 

The parameters supported by the report are defined as CM properties and must be stored in a ReportMetaDataobject. Every parameter must be defined with a namespace and a property ID, additionally a set of default values has to be specified.

static {
         m_hidden = new PropertyName("http://sap.com/test/", "hidden");

         List list = new ArrayList();
         list.add(m_hidden); 
         
         m_parameterNames = Collections.unmodifiableList(list); 
         
         m_parameterDefinitions = new HashMap();
         m_parameterDefinitions.put(m_hidden, 
                 new PropertyDef(
                          PropertyType.BOOLEAN, false, true, 
                                   false, false, false)); 
         
         m_parameterDefaults = new HashMap();
         m_parameterDefaults.put(m_hidden, Boolean.FALSE);

         m_meta = ReportInputMeta.getInstance(
                 m_parameterNames, m_parameterDefinitions, 
                 m_parameterDefaults
); 
}

Supported parameters have to be bundled in a ReportInputMetaobject and returned by the corresponding getMeta()method.

         public IReportInputMeta getMeta() throws ResourceException {
                 return SimpleReport.m_meta;
         }

To check the user input for parameters on the user interface, the verify method can be implemented for validation. If the verify method returns null, no verification is done.

         public IReportInputError verify(
                       IReportInput input, IResourceContext ctx)               throws ResourceException {               return null;
        }

For the rendering part of the report, certain methods have to be implemented for displaying a report title or description in a locale-specific way. ResourceBundles can be used for this.

public String getDisplayName(Locale locale); public String getDescription(Locale locale);

Important methods to be implemented in this interface:

Method

Purpose

execute()

Executes the report for the specified scope and stores the report result in the result receiver object.

verify()

Checks the users input of reports dialog. If no verification should be done, the method must return null.

getDisplayName()

Returns the name to be displayed in the user interface

getDescription()

Returns the description of the report for displaying on the user interface.

getMeta()

Returns the supported set of parameters of the report

Lifetime of a Report

In general, the lifetime of a report object is un determined and can be initiated often. Therefore, the constructor of a customer report should be kept very short, or use an empty default constructor.

public SimpleReport() { }

We recommend avoiding expensive operations within the reports constructor or coding that applies any side effects. Try to encapsulate most of the initialization of the report into static parts of the implementation class.

Configuration

The integration of the report into KM's configuration requires the report to be registered as a configurable object in the configuration framework. For this reason, a new class definition and an instance file have to be created during development time.

Preparing the Configurables on IDE Level

The instance (SimpleReport.co.xml) of the defined report can also be specified in development IDE. Therefore a new configuration XML file has to be created in the location:

config://install/data/cm/repository_managers/reports:

<?xml version="1.0" encoding="UTF-8" ?>

<Configurable configclass="Report">

<property name="cfg_name"value="SimpleReport"/>

<property name="class"value="com.sap.km.reporting.SimpleReport"/>

</Configurable>

The instance file has to be bundled with the deployable unit of the reports implementation. A configArchive structure will be automatically generated while the PAR file build is running.


Adding the Report to the Reporting Repository

After deployment of the report within a valid PAR file structure, the report has to be assigned to the reporting repository manager. The configuration of the reporting repository manager can be accessed via portal navigation System Administration -> System Configuration -> Knowledge Management -> Content Management -> Repository Manager -> Reporting Repository.

Open the standard reporting repository manager for editing and add the SimpleReport to the active reports list.

After adding the new custom report to the manager, save the settings and the changes will take effect immediately.

The new report is now available on the reports page of the Content Manager role.

Now the report can be scheduled and run by a Content Manager.

Example

For an example, download the file com.sap.netweaver.kmc.reporting.zip